package com.clp.protocol.iec104.apdu.asdu.infoobj.infoelem;

import com.clp.protocol.iec104.definition.Ts;
import com.clp.protocol.iec104.definition.TypeTag;
import com.clp.protocol.core.pdu.nbytepdu.BaseNBytePduClip;
import com.clp.protocol.core.pdu.ByteToStringFormat;
import io.netty.buffer.ByteBuf;
import lombok.Getter;

import java.util.Objects;
import java.util.function.Consumer;

/**
 * 双点遥信 信息元素内容
 */
@Getter
public class M_DP_NA_1_InfoElem extends TsInfoElem {

    /**
     * 有效状态
     */
    private Ts.Valid valid;
    /**
     * 当前值状态
     */
    private Ts.CurrVal currVal;
    /**
     * 被取代状态
     */
    private Ts.Replace replace;
    /**
     * 被闭锁状态
     */
    private Ts.Lock lock;
    /**
     * 开关状态
     */
    private Ts.TwoPointSwitch twoPointSwitch;

    public M_DP_NA_1_InfoElem() {
        this(null, null, null, null, null);
    }

    public M_DP_NA_1_InfoElem(boolean isValid, boolean isCurrVal, boolean isReplaced, boolean isLocked, boolean isSwitchOn) {
        super(TypeTag.M_DP_NA_1);
        this.valid = Ts.Valid.gain(isValid);
        this.currVal = Ts.CurrVal.gain(isCurrVal);
        this.replace = Ts.Replace.gain(isReplaced);
        this.lock = Ts.Lock.gain(isLocked);
        this.twoPointSwitch = Ts.TwoPointSwitch.gain(isSwitchOn);
    }

    public M_DP_NA_1_InfoElem(Ts.Valid valid, Ts.CurrVal currVal, Ts.Replace replace, Ts.Lock lock, Ts.TwoPointSwitch twoPointSwitch) {
        super(TypeTag.M_DP_NA_1);
        this.valid = valid;
        this.currVal = currVal;
        this.replace = replace;
        this.lock = lock;
        this.twoPointSwitch = twoPointSwitch;
    }

    @Override
    public M_DP_NA_1_InfoElem refreshFrom(ByteBuf buf) {
        byte[] bytes = new byte[typeTag().getInfoElemBytesLen()];
        buf.readBytes(bytes);
        byte by = bytes[0];
        this.valid = Ts.Valid.gain((by & 0x80) == 0x80 ? 1 : 0);
        this.currVal = Ts.CurrVal.gain((by & 0x40) == 0x40 ? 1 : 0);
        this.replace = Ts.Replace.gain((by & 0x20) == 0x20 ? 1 : 0);
        this.lock = Ts.Lock.gain((by & 0x10) == 0x10 ? 1 : 0);
        this.twoPointSwitch = Ts.TwoPointSwitch.gain(by & 0x03);
        return this;
    }

    @Override
    public boolean isValid() {
        if (valid == null) return false;
        if (currVal == null) return false;
        if (replace == null) return false;
        if (lock == null) return false;
        return twoPointSwitch != null;
    }

    @Override
    public void writeBytesTo(ByteBuf buf) {
        buf.writeByte(generateByte());
    }

    private byte generateByte() {
        byte by = 0x00;
        by |= (valid.getValue() == 1 ? 0x80 : 0x00);
        by |= (currVal.getValue() == 1 ? 0x40 : 0x00);
        by |= (replace.getValue() == 1 ? 0x20 : 0x00);
        by |= (lock.getValue() == 1 ? 0x10 : 0x00);
        by |= (twoPointSwitch.getValue());
        return by;
    }

    @Override
    public void writeFormattedByteStringsTo(StringBuilder sb, String frameClipBytesSeparator, String byteSeparator, ByteToStringFormat byteFormat) {
        byte by = generateByte();
        sb.append(byteFormat.format(by));
    }

    @Override
    public void writeSimpleDescriptionTo(StringBuilder sb) {
        sb.append(valid).append(", ").append(currVal).append(", ").append(replace).append(", ").append(lock).append(", ").append(twoPointSwitch);
    }

    @Override
    public void writeDetailDescriptionTo(StringBuilder sb) {
        sb.append("有效状态：").append(valid).append(", 当前值状态：").append(currVal).append(", 被取代状态：")
                .append(replace).append(", 被闭锁状态：").append(lock).append(", 开关状态：").append(twoPointSwitch);
    }

    @Override
    public boolean isTsValid() {
        return valid == Ts.Valid.VALID;
    }

    @Override
    public boolean isTsCurrVal() {
        return currVal == Ts.CurrVal.CURR_VAL;
    }

    @Override
    public boolean isTsReplaced() {
        return replace == Ts.Replace.REPLACE;
    }

    @Override
    public boolean isTsLocked() {
        return lock == Ts.Lock.LOCK;
    }

    @Override
    public boolean isTsSwitchOn() {
        return twoPointSwitch == Ts.TwoPointSwitch.SWITCH_ON;
    }

    @Override
    protected void forEachOneLevelChild(Consumer<BaseNBytePduClip<?>> consumer) {
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        M_DP_NA_1_InfoElem that = (M_DP_NA_1_InfoElem) o;
        return valid == that.valid && currVal == that.currVal && replace == that.replace && lock == that.lock && twoPointSwitch == that.twoPointSwitch;
    }

    @Override
    public int hashCode() {
        return Objects.hash(valid, currVal, replace, lock, twoPointSwitch);
    }
}
